import {
  Shader,
  ShaderData,
  ShaderProperty,
  ShaderPool,
  ShaderProgram,
  ShaderProgramPool,
  ShaderMacro,
  ShaderMacroCollection,
  ShaderDataGroup,
  ShaderLib
} from "@nirvana/shaders";
import { Vector3, Matrix4, Color } from "@nirvana/math";

import { WebGLCanvas } from "@nirvana/canvas";
import { VertexBufferData, IndexBufferData, DataElement } from "@nirvana/core";
import { parseOBJ } from "./obj.loader";

async function main() {
  const shaderMacroCollection: ShaderMacroCollection = new ShaderMacroCollection();
  console.log(shaderMacroCollection);
  const colorShaderData: ShaderData = new ShaderData(ShaderDataGroup.Material);
  console.log(ShaderDataGroup, colorShaderData);
  const pool1: ShaderProgramPool = new ShaderProgramPool();
  const pool2: ShaderProgramPool = new ShaderProgramPool();

  // 使用使用 Canvas
  let canvas = document.getElementById("engine-nirvana");
  const webCanvas = new WebGLCanvas(canvas, {
    rate: 1
  });
  const engine = webCanvas.engine;
  const gl = engine.gl;

  const skinVS = `
  attribute vec4 a_POSITION;
  attribute vec3 a_NORMAL;
  attribute vec4 a_WEIGHTS_0;
  attribute vec4 a_JOINTS_0;

  uniform mat4 u_projection;
  uniform mat4 u_view;
  uniform mat4 u_world;
  uniform sampler2D u_jointTexture;
  uniform float u_numJoints;

  varying vec3 v_normal;

  // these offsets assume the texture is 4 pixels across
  #define ROW0_U ((0.5 + 0.0) / 4.)
  #define ROW1_U ((0.5 + 1.0) / 4.)
  #define ROW2_U ((0.5 + 2.0) / 4.)
  #define ROW3_U ((0.5 + 3.0) / 4.)

  mat4 getBoneMatrix(float jointNdx) {
    float v = (jointNdx + 0.5) / u_numJoints;
    return mat4(
      texture2D(u_jointTexture, vec2(ROW0_U, v)),
      texture2D(u_jointTexture, vec2(ROW1_U, v)),
      texture2D(u_jointTexture, vec2(ROW2_U, v)),
      texture2D(u_jointTexture, vec2(ROW3_U, v)));
  }

  void main() {
    mat4 skinMatrix = getBoneMatrix(a_JOINTS_0[0]) * a_WEIGHTS_0[0] +
                      getBoneMatrix(a_JOINTS_0[1]) * a_WEIGHTS_0[1] +
                      getBoneMatrix(a_JOINTS_0[2]) * a_WEIGHTS_0[2] +
                      getBoneMatrix(a_JOINTS_0[3]) * a_WEIGHTS_0[3];
    mat4 world = u_world * skinMatrix;
    gl_Position = u_projection * u_view * world * a_POSITION;
    v_normal = mat3(world) * a_NORMAL;

    // for debugging .. see article
    //gl_Position = u_projection * u_view *  a_POSITION;
    //v_normal = a_NORMAL;
    //v_normal = a_WEIGHTS_0.xyz * 2. - 1.;
    //v_normal = a_JOINTS_0.xyz / (u_numJoints - 1.) * 2. - 1.;
  }
  `;

  const fs = `
  precision mediump float;

  varying vec3 v_normal;

  uniform vec4 u_diffuse;
  uniform vec3 u_lightDirection;

  void main () {
    vec3 normal = normalize(v_normal);
    float light = dot(u_lightDirection, normal) * .5 + .5;
    gl_FragColor = vec4(u_diffuse.rgb * light, u_diffuse.a);

    // for debugging .. see article
    //gl_FragColor = vec4(1, 0, 0, 1);
    //gl_FragColor = vec4(v_normal * .5 + .5, 1);
  }
  `;

  const meshVS = `
  attribute vec4 a_POSITION;
  attribute vec3 a_NORMAL;

  uniform mat4 u_projection;
  uniform mat4 u_view;
  uniform mat4 u_world;

  varying vec3 v_normal;

  void main() {
    gl_Position = u_projection * u_view * u_world * a_POSITION;
    v_normal = mat3(u_world) * a_NORMAL;
  }
  `;

  const skinProgram: ShaderProgram = Shader.create("skin", skinVS, fs).getShaderProgram(
    engine.gl,
    shaderMacroCollection,
    pool1
  );
  const meshProgram: ShaderProgram = Shader.create("mesh", meshVS, fs).getShaderProgram(
    engine.gl,
    shaderMacroCollection,
    pool2
  );

  let w = window.innerWidth;
  let h = window.innerHeight;
  let srate = w/h;

  const _scale = Matrix4.e.scaling(new Vector3(0.1, 0.1 * srate, 0.1));
  const _trans = Matrix4.e.translation(new Vector3(0, -1, 0));
  const rotateMatrix = _scale.clone(); //.leftDot(_trans);
  console.log(_scale, _trans);
  const shaderData: ShaderData = new ShaderData(ShaderDataGroup.Material);
  console.log(ShaderDataGroup, shaderData);
  // { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }

  let r = 0;
  const e = Matrix4.e;
  const axis = new Vector3(0.0, 1.0, 0.0);
  console.log(rotateMatrix);
  engine.update = (gl) => {
    // console.log('--');
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    // 用上面指定的颜色清除缓冲区
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.CULL_FACE);
    r += 0.01;
    rotateMatrix.rotationAxisAngle(axis, r);
    // 颜色 start 三
    const u_lightDirection = new Vector3(-1, 3, 5);
    // parts.map((part) => {
    //   colorProgram.bind();

    //   part.pBuffer.upload(colorProgram._glProgram, gl);
    //   part.nBuffer.upload(colorProgram._glProgram, gl);
    //   shaderData.setMatrix("rotateMatrix", rotateMatrix);
    //   shaderData.setMatrix("scaleMatrix", _scale);
    //   shaderData.setMatrix("u_projection", e);
    //   shaderData.setMatrix("u_view", e);
    //   shaderData.setMatrix("u_world", e);
    //   shaderData.setVector4("u_diffuse", part.u_diffuse);
    //   shaderData.setVector3("u_lightDirection", u_lightDirection);
    //   colorProgram.uploadAll(colorProgram.otherUniformBlock, shaderData);
    //   part.pBuffer.draw(gl);
    // });
    // vBuffer.upload(colorProgram._glProgram, gl);
    // iBuffer.upload(gl);
    // iBuffer.draw(gl);
  };
}

main();
